package logic;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;

import storage.Storage;
import global.CommandType.Type;
import global.Constant;
import global.Methods;
import global.Time;
import global.Task;


public class DisplayCommand extends Command {

	private ArrayList<String> filteredFileNameList;

	// case insensitive. Here it is represented in lower case
	private String searchKeyword;

	private Time searchEndTime, searchStartTime;
	private String searchTaskType;
	private String feedback;
	private boolean isExecutable;
	private Task taskAdded = null;
	private ArrayList<Task> taskDeleted = null;
	private int undoneOption;

	public DisplayCommand(String keyword, Time startingTime, Time endingTime,
			String type, int undoneOption2, boolean isExecutable,
			String parserFeedback) {
		this.isExecutable = isExecutable;
		this.feedback = parserFeedback;

		this.searchEndTime = endingTime;
		this.searchStartTime = startingTime;
		this.undoneOption = undoneOption2;

		if (searchStartTime != null && searchEndTime != null) {
			if (searchStartTime.after(searchEndTime)) {
				isExecutable = false;
				feedback = "Starting time should be earlier than ending time";
			}
		}

		this.searchTaskType = type;

		if (keyword != null) {
			this.searchKeyword = keyword.toLowerCase();
		} else {
			this.searchKeyword = null;
		}
	}

	DisplayCommand(Task newlyAddedTask) {
		taskAdded = newlyAddedTask;
	}

	DisplayCommand(ArrayList<Task> taskNewlyDeleted) {
		taskDeleted = taskNewlyDeleted;
	}

	/**@author A0105661M*/
	public ArrayList<String> execute() {
		ArrayList<String> newFeedback = new ArrayList<String>();

		if (isExecutable == true) {
			ArrayList<String> undoneList = Storage.getFileNameList();
			ArrayList<String> doneList = Storage.getDoneFileNameList();

			if (undoneOption == 2) {
				undoneList = new ArrayList<String>();
			} else if (undoneOption == 1) {
				doneList = new ArrayList<String>();
			}

			filteredFileNameList = Methods.appendStringList(undoneList,
					doneList, null, null);
			filter();
			newFeedback = display();
		}

		ExecutionHandler.setIsUndo(false);
		ExecutionHandler.setMostRecentCommandType(Type.DISPLAY);

		newFeedback.add(feedback);
		return newFeedback;
	}

	/**@author A0105661M*/
	public ArrayList<String> display() {
		try {
			ArrayList<String> result = getFormattedDisplayFeedback();
			ArchiveSecondLastDisplay();
			ArchiveLastDisplay();
			ExecutionHandler.setDisplayFileNames(filteredFileNameList);

			feedback = (filteredFileNameList.size() + " result(s) found.");

			return result;
		} catch (IOException e) {
			feedback = "Error: File Not Found";
			return new ArrayList<String>();
		}
	}

	private void ArchiveLastDisplay() {
		Task dummy = null;
		DisplayCommand lastDisplay = new DisplayCommand(dummy);
		lastDisplay.filteredFileNameList = filteredFileNameList;
		ExecutionHandler.setRecentDisplay(lastDisplay);
	}

	private void ArchiveSecondLastDisplay() {
		ArrayList<String> lastFileNameList = ExecutionHandler
				.getDisplayFileNames();
		Task dummy = null;
		DisplayCommand secondLastDisplay = new DisplayCommand(dummy);
		secondLastDisplay.filteredFileNameList = lastFileNameList;
		ExecutionHandler.setSecondRecentDisplay(secondLastDisplay);
	}

	public ArrayList<String> displayNewlyAddedTask(int index) {
		ArrayList<String> result = new ArrayList<String>();

		if (taskAdded != null) {
			String curFileName = taskAdded.getTaskFileName();
			filteredFileNameList = new ArrayList<String>();
			filteredFileNameList.add(curFileName);
			result = display();
		}

		return result;
	}

	ArrayList<String> displayTasksLeft() {
		ArrayList<String> result = new ArrayList<String>();

		if (taskDeleted != null) {
			filteredFileNameList = new ArrayList<String>();
			ArrayList<String> oldFileNameList = ExecutionHandler
					.getDisplayFileNames();
			String curFileName = "";
			for (int i = 0; i < oldFileNameList.size(); i++) {
				curFileName = oldFileNameList.get(i);
				if (!isInList(curFileName, taskDeleted)) {
					filteredFileNameList.add(curFileName);
				}
			}
			result = display();
		}

		return result;
	}

	private boolean isInList(String curFileName, ArrayList<Task> taskDeleted2) {
		for (int i = 0; i < taskDeleted2.size(); i++) {
			if (taskDeleted2.get(i).getTaskFileName()
					.equalsIgnoreCase(curFileName)) {
				return true;
			}
		}
		return false;
	}

	private ArrayList<String> getFormattedDisplayFeedback() throws IOException {

		Iterator<String> it = filteredFileNameList.iterator();
		ArrayList<String> deadlineFileNameList = new ArrayList<String>();
		ArrayList<String> multiDaynewFileNameList = new ArrayList<String>();
		ArrayList<String> NormalEventFileNameList = new ArrayList<String>();
		ArrayList<String> FloatFileNameList = new ArrayList<String>();

		String currTaskFileName;
		Task currTask;
		ArrayList<String[]> deadline = new ArrayList<String[]>();
		ArrayList<String[]> normalEvent = new ArrayList<String[]>();
		ArrayList<String[]> multiDayEvent = new ArrayList<String[]>();
		ArrayList<String[]> floatTask = new ArrayList<String[]>();

		while (it.hasNext()) {
			currTaskFileName = it.next();
			currTask = Storage.getFileContentAsTask(currTaskFileName);

			String[] curTaskString = Methods.stringToArray(currTask
					.getFormattedTaskStringNew());
			if (curTaskString.length < 1) {
				continue;
			}
			String type = curTaskString[0];

			if (type.equals("float")) {
				floatTask.add(curTaskString);
				FloatFileNameList.add(currTaskFileName);
			} else if (type.equals("deadline") && curTaskString.length >= 5) {
				deadline.add(curTaskString);
				deadlineFileNameList.add(currTaskFileName);
			} else if (type.equals("time")) {
				if (curTaskString.length < 2) {
					continue;
				}
				type = curTaskString[1];
				if (type.equals("oneDayEvent") && curTaskString.length >= 6) {
					normalEvent.add(curTaskString);
					NormalEventFileNameList.add(currTaskFileName);
				} else if (type.equals("multiDayEvent")
						&& curTaskString.length >= 8) {
					multiDayEvent.add(curTaskString);
					multiDaynewFileNameList.add(currTaskFileName);
				}
			}

		}

		filteredFileNameList = Methods.appendStringList(deadlineFileNameList,
				NormalEventFileNameList, multiDaynewFileNameList,
				FloatFileNameList);
		ArrayList<String> tempformattedFeedback = formatAllTasks(deadline,
				normalEvent, multiDayEvent, floatTask);

		return tempformattedFeedback;
	}

	private ArrayList<String> formatAllTasks(ArrayList<String[]> deadline,
			ArrayList<String[]> normalEvent, ArrayList<String[]> multiDayEvent,
			ArrayList<String[]> floatTask) {
		ArrayList<String> displayContent = new ArrayList<String>();
		String curDate = null;
		int index = 1;

		if (deadline.size() > 0) {
			displayContent.add("HEADING Deadline\n");
			curDate = null;

			for (int i = 0; i < deadline.size(); i++) {
				String[] curTask = deadline.get(i);
				String dateInfo = curTask[1] + " " + curTask[2];
				String timeInfo = curTask[3] + " ";
				String taskInfo = Methods.stringArrayToString(curTask, 5,
						curTask.length);
				if (curDate == null || !curDate.equals(dateInfo)) {
					curDate = dateInfo;
					displayContent.add("DATE " + curDate + "\n");
				}
				displayContent.add("INDEX " + index + ".  ");
				displayContent.add("TASKNAME " + taskInfo);
				displayContent.add("TIME " + timeInfo);
				index++;
			}
		}

		if (normalEvent.size() > 0) {
			displayContent.add("HEADING One day Events\n");
			curDate = null;

			for (int i = 0; i < normalEvent.size(); i++) {
				String[] curTask = normalEvent.get(i);
				String dateInfo = curTask[2] + " " + curTask[3];
				String timeInfo = Methods.stringArrayToString(curTask, 4, 7);
				String taskInfo = Methods.stringArrayToString(curTask, 7,
						curTask.length);

				if (curDate == null || !curDate.equals(dateInfo)) {
					curDate = dateInfo;
					displayContent.add("DATE " + curDate + "\n");
				}
				displayContent.add("INDEX " + index + ".  ");
				displayContent.add("TASKNAME " + taskInfo);
				displayContent.add("TIME " + timeInfo);
				index++;
			}
		}

		if (multiDayEvent.size() > 0) {
			displayContent.add("HEADING Multi-day Events\n");

			for (int i = 0; i < multiDayEvent.size(); i++) {
				String[] curTask = multiDayEvent.get(i);
				String startDateInfo = curTask[2] + " " + curTask[3] + " "
						+ curTask[4];
				String endDateInfo = curTask[5] + " " + curTask[6] + " "
						+ curTask[7];
				String taskInfo = Methods.stringArrayToString(curTask, 8,
						curTask.length);

				displayContent.add("INDEX " + index + ".  ");
				displayContent.add("TASKNAME " + taskInfo + "\n");
				displayContent.add("MULDATE " + "	Start: " + startDateInfo
						+ "\n");
				displayContent
						.add("MULDATE " + "	  End: " + endDateInfo + "\n");
				index++;
			}
		}

		if (floatTask.size() > 0) {
			displayContent.add("HEADING Unscheduled Tasks\n");
			for (int i = 0; i < floatTask.size(); i++) {
				String[] curTask = floatTask.get(i);
				String taskInfo = Methods.stringArrayToString(curTask, 1,
						curTask.length);

				displayContent.add("INDEX " + index + ".  ");
				displayContent.add("FLOATTASKNAME " + taskInfo + "\n");
				displayContent.add("\n");
				index++;
			}
		}

		return displayContent;
	}

	private void filter() {
		filterKeyword();
		filterTaskType();
		filterEndingTime();
	}

	private void filterKeyword() {
		if (searchKeyword != null) {
			Iterator<String> it = filteredFileNameList.iterator();
			String taskFileName = Constant.EMPTY_STRING;

			ArrayList<String> resultArrayList = new ArrayList<String>();

			while (it.hasNext()) {
				taskFileName = it.next().toLowerCase();
				if (taskFileName.contains(searchKeyword)) {
					resultArrayList.add(taskFileName);
				}
			}

			filteredFileNameList = resultArrayList;
		}
	}

	private void filterTaskType() {
		if (searchTaskType != null) {
			// float "0"
			// time "1"
			// deadline "2"
			String taskTypeString = determineTaskTypeString();
			String taskTypeCharAsString = Constant.EMPTY_STRING;
			String taskFileName = Constant.EMPTY_STRING;
			Iterator<String> it = filteredFileNameList.iterator();

			ArrayList<String> resultArrayList = new ArrayList<String>();

			while (it.hasNext()) {
				taskFileName = it.next();
				taskTypeCharAsString = getTaskTypeCharAsString(taskFileName);

				if (taskTypeCharAsString.equalsIgnoreCase(taskTypeString)) {
					resultArrayList.add(taskFileName);
				}
			}

			filteredFileNameList = resultArrayList;
		}
	}

	private void filterEndingTime() {
		if (searchEndTime != null) {
			Iterator<String> it = filteredFileNameList.iterator();
			String taskFileName = Constant.EMPTY_STRING;
			String timeString = Constant.EMPTY_STRING;
			Time currTaskDeadline;

			ArrayList<String> resultArrayList = new ArrayList<String>();

			while (it.hasNext()) {
				taskFileName = it.next();
				timeString = getTimeString(taskFileName);

				if (timeString != null) {
					assert (timeString.length() == 12);
					currTaskDeadline = new Time(timeString);

					if (searchStartTime == null) {
						if (currTaskDeadline.before(searchEndTime)
								|| currTaskDeadline.equals(searchEndTime)) {
							resultArrayList.add(taskFileName);
						} else {
							continue;
						}
					} else {
						if ((currTaskDeadline.before(searchEndTime) || currTaskDeadline
								.equals(searchEndTime))
								&& (currTaskDeadline.after(searchStartTime) || currTaskDeadline
										.equals(searchStartTime))) {
							resultArrayList.add(taskFileName);
						} else {
							continue;
						}
					}

				}
			}

			filteredFileNameList = resultArrayList;
		}
	}

	private String getTimeString(String fileName) {
		if (fileName.charAt(0) != '0') {
			return fileName.substring(0, 12);
		} else {
			return null;
		}
	}

	private String getTaskTypeCharAsString(String str) {
		assert (str != null && str.length() > 0);
		return str.substring((str.length() - 5), (str.length() - 4));
	}

	private String determineTaskTypeString() {
		String taskTypeString;

		if (searchTaskType == null) {
			taskTypeString = null;
		} else {
			if (searchTaskType.equalsIgnoreCase(Constant.FLOAT_TASK_TYPE)) {
				taskTypeString = "0";
			} else if (searchTaskType.equalsIgnoreCase(Constant.TIME_TASK_TYPE)) {
				taskTypeString = "1";
			} else {
				taskTypeString = "2";
			}
		}

		return taskTypeString;
	}

	public void print() {
		System.out.println(filteredFileNameList);
	}

	public String getTestFeedback() {
		String keyword = "null";
		if (!searchKeyword.equals(Constant.EMPTY_STRING)){
			keyword = searchKeyword;
		}
		
		String feedback = isExecutable + " " + keyword + " "
				+ searchStartTime + " " + searchEndTime + " " + searchTaskType
				+ " " + undoneOption;
		return feedback;
	}

}
